/*
 *  Autores: Claudio Djohnnatha, David Guilherme, Jailson Lima e Jordan Lira.
 *
 *  Projeto da disciplina Linguagem de Programação 2.
 *
 *  Arquivo: ProtocolWrite.java
 *
 *  Descrição: Define os protocolos de escrita no Painel de Texto do EditorOnline do ClientApplication.
 *
 *  Data: 27/08/2013
 *
 */



import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.awt.Color;

public class ProtocolWrite
{
   // Editor.
   private EditorOnline editor;

   // Painel de Texto.
   private MyTextPane pane;

   // Saída para o servidor.
   private DataOutputStream out;

   // Variáveis para saber se as teclas DELETE, BACKSPACE e SPACE foram pressionadas.
   private boolean delete = false;
   private boolean backspace = false;
   private boolean space = false;
   private boolean enter = false;
   private boolean tab = false;

   public ProtocolWrite( EditorOnline e )
   {
      // Editor.
      editor = e;

      // Painel de Texto.
      pane = editor.getTextPane();

      // Evento de teclado de pane.
      pane.addKeyListener(
         new KeyAdapter() // classe interna anônima.
         {
            public void keyPressed( KeyEvent event )
            {
               if ( !pane.isEditable() )
               {
                  event.consume();
                  return;
               }

               if ( event.getKeyCode() == KeyEvent.VK_DELETE )
               {
                  delete = true;
                  event.consume();
               }

               if ( event.getKeyCode() == KeyEvent.VK_BACK_SPACE )
               {
                  backspace = true;
                  event.consume();
               }

               if ( event.getKeyCode() == KeyEvent.VK_SPACE )
               {
                  space = true;
                  event.consume();
               }

               if ( event.getKeyCode() == KeyEvent.VK_ENTER )
               {
                  enter = true;
                  event.consume();
               }

               if ( event.getKeyCode() == KeyEvent.VK_TAB )
               {
                  tab = true;
                  event.consume();
               }

            }

            public void keyTyped( KeyEvent event )
            {
               if ( !pane.isEditable() )
               {
                  event.consume();
                  return;
               }

               int position = pane.getCaretPositionSync();

               try
               {
                  if ( delete )
                  {
                     delete = false;
                     if ( position != pane.getTextSync().length() )
                        out.writeUTF( "DELETE " + position + " " + pane.getTextSync().length() + " W" );
                     event.consume();
                     return;
                  }

                  if ( backspace )
                  {
                     backspace = false;
                     if ( position != 0 )
                        out.writeUTF( "BACKSPACE " + position + " " + pane.getTextSync().length() + " W" );
                     event.consume();
                     return;
                  }

                  if ( space )
                  {
                     space = false;
                     out.writeUTF( "SPACE " + position + " " + pane.getTextSync().length() + " W" );
                     event.consume();
                     return;
                  }

                  if ( enter )
                  {
                     enter = false;
                     out.writeUTF( "ENTER " + position + " " + pane.getTextSync().length() + " W" );
                     event.consume();
                     return;
                  }

                  if ( tab )
                  {
                     tab = false;
                     out.writeUTF( "TAB " + position + " " + pane.getTextSync().length() + " W" );
                     event.consume();
                     return;
                  }

                  out.writeUTF( "CHARACTER " + position + " " + pane.getTextSync().length() + " " + event.getKeyChar() + " W" );
                  event.consume();
               }
               catch ( IOException e )
               {

               }
            }
         }
      ); // fim do método addKeyListener.

   } // fim do construtor.

   // Configura a referência para o ProtocolWrite do stream de saída (out) do ClientApplication, que irá se
   // conectar ao stream de entrada (in) do ProtocolServer associado a esse ClientApplication.
   public void setOutput( DataOutputStream out )
   {
      this.out = out;
   }

   // Método para escrever o texto sincrônizado pelo ProtocolComunication no Painel de Texto do editor. 
   public void writeTextPane( String fromServer )
   {
      String[] tokens = fromServer.split( " " );
      String text;

      // tokens[ 0 ] .. tokens[ tokens.length - 4 ] => text
      // tokens[ tokens.length - 3 ] => DELETE/BACKSPACE/CHARACTER
      // tokens[ tokens.length - 2 ] => position
      // tokens[ tokens.length - 1 ] => MYSELF/OTHER

      // PRIMEIRA COMUNICAÇÃO COM O SERVIDOR.
      if ( tokens[ tokens.length - 1 ].equals( "ACCEPT_CONNECTING" ) ) // tokens[ tokens.length - 1 ].equals( "ACCEPT_CONNECTING" )
      {
         editor.updateListDocuments( fromServer );
         return;
      }

      int firstIndex = fromServer.lastIndexOf( "DOC" );

      String doc = firstIndex < 0 ? "" : fromServer.substring( firstIndex, fromServer.length() );

      if( doc.equals("DOC") ) // Operações sobre os arquivos de servidor
      {
         switch ( tokens[ tokens.length - 1 ].charAt( 0 ) )
         {
            case 'L': // LIST_DOC
            
               editor.updateListDocuments( fromServer );
               editor.showMessageServer( "Documentos Atualizados!" );
               return;

            case 'N': // NEW_DOC

               editor.enableTitle();
               pane.setEnabled( true );
               pane.setBackground( new Color( 255, 255, 255 ) );
               pane.setText( "" );
               pane.grabFocus();
               return;

            case 'O': // OPEN_DOC

               if ( tokens[ tokens.length - 2 ].equals( "OK" ) )
               {
                  text = fromServer.substring( 0, fromServer.lastIndexOf( " OK OPEN_DOC" ) );
                  editor.enableTitle();
                  pane.setEnabled( true );
                  pane.setBackground( new Color( 255, 255, 255 ) );
                  pane.setText( text );
                  pane.grabFocus();
                  pane.setCaretPosition( text.length() );
               }
               else // tokens[ tokens.length - 2 ] só pode ser FAIL.
               {
                  editor.showMessageServer( "Documento nao encontrado!" );
                  editor.disableTitle();
                  pane.setText( "" );
                  pane.setEnabled( false );
                  pane.setBackground( new Color( 225, 225, 225 ) );
               }
                  

               return;

            case 'S': // SAVE_DOC

               editor.showMessageServer( "Documento salvo no servidor!" );
               return;

            case 'C': // CLOSE_DOC

               editor.disableTitle();
               pane.setEnabled( false );
               pane.setBackground( new Color( 225, 225, 225 ) );
               pane.setText( "" );
               return;

            case 'R': // RENAME_DOC

               String new_title = fromServer.substring( 0, fromServer.lastIndexOf( " RENAME_DOC" ) );
               editor.renameTitle( new_title );
               return;

            case 'D': //DELETE_DOC

               if ( tokens[ tokens.length - 2 ].equals( "OK" ) ) // só pode ser OK ou FAIL.
               {
                  editor.disableTitle();
                  pane.setEnabled( false );
                  pane.setBackground( new Color( 225, 225, 225 ) );
                  pane.setText( "" );
                  editor.updateListDocuments( fromServer.substring( 0, fromServer.lastIndexOf( " DELETE_DOC" ) ) );
                  editor.showMessageServer( "Documento Excluido!" );
               }
               else // tokens[ tokens.length - 2 ] só pode ser FAIL.
               {
                  editor.showMessageServer( "Falha ao Excluir Documento!" );
               }
               return;

         } // fim switch 
      }
      else // Operações de escrita
      {
         int current_position = pane.getCaretPositionSync();
         int new_position = Integer.parseInt( tokens[ tokens.length - 2 ] ); // representa a posição do cursor de que alterou o texto.

         switch( tokens[ tokens.length - 3 ].charAt( 0 ) )
         {
            case 'C':
            
               text = fromServer.substring( 0, fromServer.lastIndexOf( " CHARACTER" ) );
               // pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) )
                  pane.setTextAndSetPosition( text, text.length() < current_position + 1 ? text.length() : current_position + 1 );
               else // OTHER.
                  if ( new_position < current_position )
                     pane.setTextAndSetPosition( text, current_position + 1 );
                  else
                     pane.setTextAndSetPosition( text, current_position );

            break;
            case 'S':

               text = fromServer.substring( 0, fromServer.lastIndexOf( " SPACE" ) );
               // pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) )
                  pane.setTextAndSetPosition( text, text.length() < current_position + 1 ? text.length() : current_position + 1 );
               else // OTHER.
                  if ( new_position < current_position )
                     pane.setTextAndSetPosition( text, current_position + 1 );
                  else
                     pane.setTextAndSetPosition( text, current_position );
            
            break;
            case 'E':

               text = fromServer.substring( 0, fromServer.lastIndexOf( " ENTER" ) );
               //pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) )
                  pane.setTextAndSetPosition( text, text.length() < current_position + 1 ? text.length() : current_position + 1 );
               else // OTHER.
                  if ( new_position < current_position )
                     pane.setTextAndSetPosition( text, current_position + 1 );
                  else
                     pane.setTextAndSetPosition( text, current_position );

            break;
            case 'T':

               text = fromServer.substring( 0, fromServer.lastIndexOf( " TAB" ) );
               //pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) )
                  pane.setTextAndSetPosition( text, text.length() < current_position + 1 ? text.length() : current_position + 1 );
               else // OTHER.
                  if ( new_position < current_position )
                     pane.setTextAndSetPosition( text, current_position + 1 );
                  else
                     pane.setTextAndSetPosition( text, current_position );

            break;
            case 'D':

               text = fromServer.substring( 0, fromServer.lastIndexOf( " DELETE" ) );
               // pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) )
                  pane.setTextAndSetPosition( text, text.length() < current_position ? text.length() : current_position );
               else // OTHER.
                  if ( new_position < current_position )
                     pane.setTextAndSetPosition( text, current_position - 1 );
                  else
                     pane.setTextAndSetPosition( text, current_position );

            break;
            case 'B':

               text = fromServer.substring( 0, fromServer.lastIndexOf( " BACKSPACE" ) );
               //pane.setText( text );

               if ( tokens[ tokens.length - 1 ].equals( "MYSELF" ) && current_position != 0 )
                  pane.setTextAndSetPosition( text, text.length() < current_position - 1 ? text.length() : current_position - 1 );

               else // OTHER.
                  if ( new_position > current_position )
                     pane.setTextAndSetPosition( text, current_position );
                  else
                     pane.setTextAndSetPosition( text, current_position - 1 );
            
            break;
         } // fim switch
      
      } // fim else

   } // fim do método writeTextPane.

   public void desconnecting()
   {
      try { out.writeUTF( "DESCONNECTING" ); } catch ( IOException e ) {}
   }

   public void listDocuments()
   {
      try { out.writeUTF( "LIST_DOC F" ); } catch ( IOException e ) {}
   }

   public void newDocument( String title )
   {
      try { out.writeUTF( title + " NEW_DOC F" ); } catch ( IOException e ) {}
   }

   public void openDocument( String title )
   {
      try { out.writeUTF( title + " OPEN_DOC F" ); } catch ( IOException e ) {}
   }

   public void saveDocument()
   {
      try { out.writeUTF( "SAVE_DOC F" ); } catch ( IOException e ) {}
   }

   public void closeDocument()
   {
      try { out.writeUTF( "CLOSE_DOC F" ); } catch ( IOException e ) {}
   }

   public void renameDocument( String name )
   {
      try { out.writeUTF( name + " RENAME_DOC F" ); } catch ( IOException e ) {} 
   }

   public void deleteDocument()
   {
      try { out.writeUTF( "DELETE_DOC F" ); } catch ( IOException e ) {}
   }

}